/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#ifndef MOE_OBJECT_TYPE_MANAGER_H
#define MOE_OBJECT_TYPE_MANAGER_H

#include "ClassMetaProxy.h"
#include "CommonDef.h"
#include "RawByteVector.h"

#include <boost/noncopyable.hpp>
#include <boost/unordered_map.hpp>

namespace MOE
{

class ObjectTypeManager : boost::noncopyable
{
public:

	static ObjectTypeManager& GetSingleton()
	{
		static ObjectTypeManager singleton;
		return singleton;
	}

	template <class T>
	ClassMetaProxy RegisterClass(const RawByteVector& className)
	{
		ClassMetaHolderBase* ptr = ClassMetaHolder<T>::Instance();
		ClassIDType id = ClassMetaHolder<T>::ID();

		return RegisterClassInternal(ptr, id, className, sizeof(T), AT_NonAtom);
	}

	template <class T>
	static ClassIDType GetClassID()
	{
		return ClassMetaHolder<T>::ID();
	}

	ClassIDType GetClassID(const RawByteVector& className) const;

	template <class T>
	ClassMetaProxy GetClassMeta() const
	{
		return GetClassMeta(ClassMetaHolder<T>::ID());
	}

	ClassMetaProxy GetClassMeta(const ClassIDType classID) const;
	ClassMetaProxy GetClassMeta(const RawByteVector& className) const;

private:
	struct ClassMetaHolderBase
	{
		ClassMetaHolderBase() : _meta(NULL) {}

		ClassIDType GetID() const
		{
			return reinterpret_cast<ClassIDType>(this);
		}

		ClassMeta* _meta;
	};

	template <class T>
	struct ClassMetaHolder : public ClassMetaHolderBase
	{
		static ClassIDType ID()
		{
			return Instance()->GetID();
		}

		static ClassMetaHolderBase* Instance()
		{
			static ClassMetaHolderBase inst;
			return &inst;
		}
	};

	typedef boost::unordered_map<ClassIDType, ClassMetaHolderBase*> IDToMetaMap;
	typedef boost::unordered_map<RawByteVector, ClassMetaHolderBase*> NameToMetaMap;

	ObjectTypeManager();

	void RegisterAtomClasses();
	ClassMetaProxy RegisterClassInternal(ClassMetaHolderBase* holder, ClassIDType id, const RawByteVector& className, size_t classSize, AtomTypes atomType);

	IDToMetaMap _idToMeta;
	NameToMetaMap _nameToMeta;
};

}

#endif
